/// <reference path="../devextreme/ts/jquery.d.ts" />
/// <reference path="../devextreme/ts/dx.all.d.ts" />

(function ($) {
    class DataGridView {
        constructor(options) {
            const defaultOptions = {
                remoteOperations: options.remoteOperations ?? true,
                showBorders: true,
                paging: options.paging || { pageIndex: 0, pageSize: 20 },
                pager: options.pager || {
                    allowedPageSizes: options.allowedPageSizes || [5, 10, 20, 25, 30, 50],
                    displayMode: 'full',
                    infoText: '第{0}/{1}页，共{2}条',
                    showPageSizeSelector: true,
                    showInfo: true,
                    showNavigationButtons: true,
                    visible: true,
                },
                selection: options.selection || {
                    mode: 'multiple',
                    showCheckBoxesMode: 'none',
                    selectAllMode: 'page',
                },
                hoverStateEnabled: true,
                dataSource: {
                    load: loadOptions => {
                        return this.load(loadOptions);
                    },
                    key: options.key || 'oid',
                },
                // 行点击
                onRowClick: e => {
                    if (this.options.onRowClick) {
                        this.options.onRowClick(e.key, e.data);
                    }
                },
                // 行双击
                onRowDblClick: e => {
                    if (this.options.onRowDblClick) {
                        this.options.onRowDblClick(e.key, e.data);
                    }
                },
                // 选中行改变
                onSelectionChanged: e => {
                    if (this.options.onSelectionChanged) {
                        this.options.onSelectionChanged({
                            selectedRowsData: e.selectedRowsData,
                            selectedRowKeys: e.selectedRowKeys,
                            currentSelectedRowKeys: e.currentSelectedRowKeys,
                            currentDeselectedRowKeys: e.currentDeselectedRowKeys,
                        });
                    }
                },
                onRowPrepared: e => {
                    if (e.rowType && e.rowType === 'data') {
                        if (this.rowStyles && this.rowStyles.length > 0) {
                            // 执行表达式
                            const rowStyle = this.rowStyles.find(x => x.expression.evaluate({ item: e.data }));
                            if (rowStyle) {
                                e.rowElement.addClass(rowStyle.className);
                            }
                        }
                    }
                    if (this.options.onRowPrepared) {
                        this.options.onRowPrepared(e);
                    }
                },
                onContextMenuPreparing: e => {
                    if (e.target === 'content' && e.row) {
                        if (this.options.getContextMenuItems) {
                            e.component.selectRowsByIndexes(e.rowIndex);
                            let contextMenuItems = this.options.getContextMenuItems();
                            if (contextMenuItems instanceof Array && contextMenuItems.length > 0) {
                                e.items = contextMenuItems.map(item => {
                                    const visible = item.visible;
                                    item = item.options ?? item;
                                    return {
                                        text: item.text,
                                        icon: item.icon,
                                        key: e.row.key,
                                        width: '200px',
                                        items: item.items,
                                        visible: visible,
                                        onItemClick: ({ itemData }) => {
                                            if (item.onClick) {
                                                item.onClick(itemData.key);
                                            }
                                        },
                                    };
                                });
                            }
                        }
                    }
                },
                onCellClick: e => {
                    if (e.rowType == 'header' && e.column.allowSorting) {
                        e.component.pageIndex(0); // 页码返回第一页
                    }
                },
                onCellPrepared: options.onCellPrepared,
                toolbar: options.toolbar,
                masterDetail: options.masterDetail,
                sorting: options.sorting || {},
                stateStoring: {
                    enabled: true,
                    type: 'custom',
                    customSave: state => this.saveColumns(state.columns)
                },
                columnAutoWidth: options.columnAutoWidth || false
            };
            if (options.noKey) {
                delete defaultOptions.dataSource.key;
            }
            const dataGridOptions = this.initOptions(defaultOptions);
            this.options = options;
            this.$element = this.options.$element;
            this.first = true;
            this.columns = [];
            this.rowStyles = [];
            this.cacheData = null;
            this.others = {};
            this.init(this.$element, dataGridOptions);
        }
        load(loadOptions) {
            // 每次加载或刷新时清空选择
            this.dataGridView.clearSelection();

            // 如果有缓存数据，直接返回缓存数据，并且清空缓存数据
            if (this.cacheData) {
                return new Promise(resolve => {
                    resolve(this.cacheData);
                    this.cacheData = null;
                });
            }
            if (this.options.onLoad) {
                loadOptions = { ...loadOptions, ...this.others };
                return this.options.onLoad(loadOptions).then(result => {
                    result.data = result.data ?? { columns: [], rows: [], totalCount: 0 };
                    if (result.data.columns && typeof result.data.columns === 'string') {
                        result.data.columns = JSON.parse(result.data.columns)
                    }
                    if (result.data.rowStyles && typeof result.data.rowStyles === 'string') {
                        result.data.rowStyles = JSON.parse(result.data.rowStyles)
                    }
                    result = result.data;
                    const datasource = {
                        data: result.rows,
                        totalCount: result.totalCount,
                    };

                    if (this.options.rowFilter) {
                        datasource.data = this.options.rowFilter(datasource.data, loadOptions);
                    }

                    if (this.first) {
                        this.setConfig(result);
                        this.first = false;
                        // 缓存数据
                        // 在第一次加载列的时候，dataGrid会重新加载一次load，所以在第一次请求的时候，缓存数据，防止重复请求
                        this.cacheData = result.columns && result.columns instanceof Array && result.columns.length > 0 ? datasource : null;
                    }

                    return datasource;
                });
            } else {
                return new Promise(resolve => {
                    resolve({ data: [], totalCount: 0 });
                });
            }
        }
        init($element, options) {
            this.dataGridView = $element.dxDataGrid(options).dxDataGrid('instance');
        }
        // 初始化操作列
        initOperationColumn() {
            let operations = this.options.getOperations ? this.options.getOperations() : [];
            if (operations instanceof Array && operations.length > 0) {
                operations = operations.map(operation => {
                    if (operation.options) {
                        return { ...operation.options, visible: operation.visible };
                    }
                    return operation;
                });
                return {
                    dataField: '',
                    alignment: 'center',
                    cssClass: 'operation-column',
                    width: '110px',
                    allowResizing: false,
                    allowReordering: false,
                    cellTemplate(container, options) {
                        // 展示下拉选项
                        $('<div />')
                            .dxDropDownButton({
                                text: '操作',
                                width: '100%',
                                stylingMode: 'text',
                                focusStateEnabled: false,
                                items: operations.map(o => { return { key: options.key, ...o } }),
                                dropDownOptions: {
                                    minWidth: '200px',
                                },
                                onButtonClick(e) {
                                    // 阻止冒泡
                                    //e.event.stopPropagation();
                                }
                            })
                            .appendTo(container);
                    },
                };
            }
        }
        // 初始化列
        initColumns(columns) {
            if (columns.length > 0) {
                let operationColumn = this.initOperationColumn();
                columns = columns.map(column => {
                    if ((!column.width) && !this.options.columnAutoWidth) {
                        column.width = '120px';
                    }
                    if (column.customizeText) {
                        let customizeText = column.customizeText;
                        column.customizeText = ({ value }) => {
                            if (value !== undefined) {
                                // 0 要进去计算
                                return exprEval.Parser.evaluate(customizeText, { value })
                            }
                            return '';
                        }
                    }
                    if (column.dataType === 'datetime') {
                        column.format = ris.formatDateTime;
                        column.width = '160px';
                    }
                    return column;
                });
                this.dataGridView.option(
                    'columns',
                    operationColumn ? [operationColumn, ...columns] : columns
                );
                this.loadColumns();
            }
        }
        loadColumns() {
            if (this.options.id) {
                let columns = localStorage.getItem(`data-grid-columns-${this.options.id}`);
                if (columns) {
                    columns = JSON.parse(columns);
                    const gridColumns = this.dataGridView.option('columns');
                    const newColumns = [];
                    for (const column of columns) {
                        const gridColumn = gridColumns.find(x => x.dataField === column.dataField);
                        if (gridColumn) {
                            newColumns.push({ ...gridColumn, ...column });
                        }
                    }
                    const oldColumns = [];
                    for (const column of gridColumns) {
                        if (!newColumns.find(x => x.dataField === column.dataField)) {
                            oldColumns.push(column);
                        }
                    }
                    this.dataGridView.option('columns', [...oldColumns, ...newColumns]);
                }
            }
        }
        saveColumns(columns) {
            if (this.options.id && columns) {
                columns = columns
                    .filter(column => column.dataField)
                    .sort((x, y) => x.visibleIndex - y.visibleIndex)
                    .map(column => {
                        return {
                            dataField: column.dataField,
                            width: column.width,
                        };
                    });
                localStorage.setItem(`data-grid-columns-${this.options.id}`, JSON.stringify(columns));
            }
        }
        setConfig(result) {
            // 配置列和样式
            if (result.columns && result.columns instanceof Array && result.columns.length > 0) {
                this.initColumns(result.columns);
                this.columns = result.columns;
            }
            if (result.rowStyles) {
                this.rowStyles = result.rowStyles.map(e => {
                    return { expression: exprEval.Parser.parse(e.expression), className: e.className };
                });
            }
        }
        // 初始化配置
        initOptions(defaultOptions) {
            return {
                remoteOperations: true,
                ...defaultOptions,
                noDataText: '未查询到数据',
                showColumnLines: true,
                columnResizingMode: 'widget',
                allowColumnResizing: true,
                allowColumnReordering: true,
                width: '100%'
            };
        }
        // 刷新
        refresh(others = {}) {
            this.others = { ...others };
            this.dataGridView.refresh();
        }
        reload(others = {}) {
            this.first = true;
            this.others = { ...others };
            this.dataGridView.refresh();
        }
        // 设置行选中
        selectRows(keys) {
            this.dataGridView.selectRows(keys, true);
        }
        // 取消行选中
        unSelectRows(keys) {
            this.dataGridView.deselectRows(keys);
        }
        // 获取选中的数据
        getSelectedRowKeys() {
            return this.dataGridView.getSelectedRowKeys();
        }
        // 获取选中的数据
        getSelectedRowsData() {
            return this.dataGridView.getSelectedRowsData();
        }
        getTotalCount() {
            return this.dataGridView.totalCount();
        }
        // 清空排序
        clearSorting() {
            this.dataGridView.clearSorting();
        }
        // 全选
        selectAll() {
            this.dataGridView.selectAll();
        }
        unselectAll() {
            this.dataGridView.clearSelection();
        }
        // 反选
        invertSelect() {
            // 获取当前选中的行数据
            var selectedRowKeys = this.dataGridView.getSelectedRowKeys();
            // 遍历所有行并反选
            this.dataGridView.selectAll();
            selectedRowKeys.forEach((key) => {
                this.dataGridView.deselectRows(key);
            });
        }
        getOption(optionName) {
            if (optionName) {
                this.dataGridView.option(optionName);
            }
        }
        setOption(optionName, option) {
            if (optionName) {
                this.dataGridView.option(optionName, option);
            }
        }
        totalCount() {
            return this.dataGridView.totalCount();
        }
        instance() {
            return this.dataGridView;
        }
    }
    $.fn.dataGrid = function (options) {
        options ??= {};
        const dataGridView = new DataGridView({ $element: $(this[0]), ...options });
        return {
            refresh: dataGridView.refresh.bind(dataGridView),
            reload: dataGridView.reload.bind(dataGridView),
            selectRows: dataGridView.selectRows.bind(dataGridView),
            unSelectRows: dataGridView.unSelectRows.bind(dataGridView),
            getSelectedRowKeys: dataGridView.getSelectedRowKeys.bind(dataGridView),
            getSelectedRowsData: dataGridView.getSelectedRowsData.bind(dataGridView),
            getTotalCount: dataGridView.getTotalCount.bind(dataGridView),
            clearSorting: dataGridView.clearSorting.bind(dataGridView),
            selectAll: dataGridView.selectAll.bind(dataGridView),
            unselectAll: dataGridView.unselectAll.bind(dataGridView),
            invertSelect: dataGridView.invertSelect.bind(dataGridView),
            getOption: dataGridView.getOption.bind(dataGridView),
            setOption: dataGridView.setOption.bind(dataGridView),
            totalCount: dataGridView.totalCount.bind(dataGridView),
            instance: dataGridView.instance.bind(dataGridView)
        };
    };
})(jQuery);
